﻿using Devil;
using System.IO;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;

namespace GameToolkit.Editor
{
    public partial class MakeABUtil
    {
        [System.Serializable]
        public class MakeABConfig : ProjectConfiguration.Configurable
        {

            [HideInInspector]
            public int dropGroup;
            //[Mask(typeof(EAssetFilter), IsIndexEnum = false)]
            [HideInInspector]
            public bool m_UsedByAssetsUtil = true;
            [HideInInspector]
            public bool m_CacheAbList = true;
            [HideInInspector]
            public string m_Destination = "Assets/StreamingAssets";
            [HideInInspector]
            public EAssetFilter m_AssetFilter = DEFAULT_ASSET_FILTER;
            [HideInInspector]
            public BuildTarget m_BuildTarget = BuildTarget.NoTarget;
            [HideInInspector]
            public BuildAssetBundleOptions m_BuildOption;
            //[HideInInspector]
            //public string m_AutoVariants;

            //public bool m_ResolveAssetsProblem;
            [HideInInspector]
            public string inAb;
            [HideInInspector]
            public string dependentAb;
            [HideInInspector]
            public string notDependentAb;
            [HideInInspector]
            public bool detailSearchMode;

            [HideInInspector]
            public string assertAsset = "";

            // 资源路径重定向
            //public bool m_RedirectAsset;
            [HideInInspector]
            public string m_RedirectVersion;
            [HideInInspector]
            public string m_GUIDFolder;

            ParallelDispatcher.Handler mExecJob;

            readonly string[] mSearchDependencyMod = { "Simple Info.", "Detail Info."};

            //GUIContent prefix = new GUIContent();

            //[InitializeOnLoadMethodParallel(IsOnMainThread = true, ExecutionOrder = InitializeOrder.AfterDefault)]
            //static void AutoUpdateVariantsPattern()
            //{
            //    var cfg = ProjectConfiguration.GetConfigurable<MakeABConfig>();
            //    UpdateVariantsPattern(cfg == null ? "cn,en" : cfg.m_AutoVariants);
            //}
            //public static void UpdateVariantsPattern(string variants)
            //{
            //    var matchs = string.IsNullOrEmpty(variants) ? null :
            //    Regex.Matches(variants, "(?<= |\t|;|,|^)[a-z0-9_]+(?= |\t|;|,|$)", RegexOptions.IgnoreCase);
            //    if (matchs != null && matchs.Count > 0)
            //    {
            //        var buf = ParallelUtils.GetBuilder();
            //        var pathbuf = ParallelUtils.GetBuilder();
            //        buf.Append("(?<=.+/)(");
            //        pathbuf.Append("(?<=.+)/(");
            //        bool first = true;
            //        foreach (Match m in matchs)
            //        {
            //            if (first)
            //                first = false;
            //            else
            //            {
            //                buf.Append('|');
            //                pathbuf.Append('|');
            //            }
            //            buf.Append(m.Value);
            //            pathbuf.Append(m.Value);
            //        }
            //        buf.Append(")(?=/.+)");
            //        pathbuf.Append(")/(?=.+)");
            //        MakeAB.mVariantsPattern = new Regex(ParallelUtils.ReturnRelease(buf), RegexOptions.IgnoreCase);
            //        MakeAB.mReplaceVariantPathPattern = new Regex(ParallelUtils.ReturnRelease(pathbuf), RegexOptions.IgnoreCase);
            //    }
            //    else
            //    {
            //        MakeAB.mVariantsPattern = null;
            //        MakeAB.mReplaceVariantPathPattern = null;
            //    }
            //}

            public override void OnGUI()
            {
                var dirty = false;

                BuildABGUI(ref dirty);

                RedirectAssetGUI(ref dirty);

                ResovleAssetsGUI(ref dirty);

                if (dirty)
                    SetDirty();
            }

            void BuildABGUI(ref bool dirty)
            {
                var drop = QuickGUI.BeginGroup("Build AssetBundle", dropGroup == 0);
                dirty |= drop ^ (dropGroup == 0);
                bool search = false, build = false;
                if (drop)
                {
                    dropGroup = 0;
                    var assetfilter = m_AssetFilter;// (EAssetFilter)EditorPrefs.GetInt("MakeAB.filter", (int)DEFAULT_ASSET_FILTER);
                    var tog = m_UsedByAssetsUtil;
                    var foreditor = EditorGUILayout.Toggle("Used By AssetsUtil", tog);
                    if (foreditor != tog)
                    {
                        dirty = true;
                        m_UsedByAssetsUtil = true;
                        //EditorPrefs.SetBool("MakeAB.assetsUtil", foreditor);
                        if (tog)
                            InnerAssetsUtil.InnerBundle = null;
                        else /*if (EditorApplication.isPlaying)*/
                            InnerAssetsUtil.InnerBundle = new ABMakeInfo();
                    }
                    tog = m_CacheAbList;// EditorPrefs.GetBool("MakeAB.cache", false);
                    var cache = EditorGUILayout.Toggle("Cache ABList", tog);
                    if (cache != tog)
                    {
                        dirty = true;
                        m_CacheAbList = tog;
                        //EditorPrefs.SetBool("MakeAB.cache", cache);
                    }

                    var str = m_Destination;// EditorPrefs.GetString("MakeAB.output", "Assets/StreamingAssets");
                    EditorGUILayout.BeginHorizontal();
                    var output = EditorGUILayout.TextField("Destination", str);
                    var sel = GUILayout.Button("Select", GUILayout.Width(60));
                    var repath = sel ? EditorUtility.OpenFolderPanel("Save AssetBundle", NativeFileSystem.GetFolderName(output), NativeFileSystem.GetFileName(output, false)) : output;
                    if (!string.IsNullOrEmpty(repath))
                        output = repath;
                    EditorGUILayout.EndHorizontal();

                    if (output != str)
                    {
                        dirty = true;
                        m_Destination = output;
                        //EditorPrefs.SetString("MakeAB.output", output);
                    }

                    EditorGUILayout.BeginHorizontal();
                    var filter = (EAssetFilter)EditorGUILayout.EnumFlagsField("Assets Filter", assetfilter);
                    EditorGUI.BeginDisabledGroup(filter == DEFAULT_ASSET_FILTER);
                    if (GUILayout.Button("Reset", GUILayout.Width(60)))
                    {
                        filter = DEFAULT_ASSET_FILTER;
                    }
                    EditorGUI.EndDisabledGroup();
                    if (filter != assetfilter)
                    {
                        dirty = true;
                        m_AssetFilter = filter;
                        //EditorPrefs.SetInt("MakeAB.filter", (int)filter);
                    }
                    EditorGUILayout.EndHorizontal();

                    //var variants = m_AutoVariants;
                    //m_AutoVariants = EditorGUILayout.TextField("Auto Variants", variants);
                    //if (variants != m_AutoVariants)
                    //{
                    //    UpdateVariantsPattern(m_AutoVariants);
                    //}
                    //prefix.text = "Keep Shader Keywords";
                    //prefix.tooltip = "设置打包时不被提出的 Keywords (分隔符： ,;)";
                    //var keywords = EditorGUILayout.TextField(prefix, m_KeepShaderKeywords ?? "");
                    //if (keywords != m_KeepShaderKeywords)
                    //{
                    //    dirty = true;
                    //    m_KeepShaderKeywords = keywords;
                    //}
                    //prefix.text = "Strip Unused Shaders";
                    //prefix.tooltip = "Remove unused shader keywords.";
                    //var strip = EditorGUILayout.Toggle(prefix, m_StripUnusedShaders);
                    //if(strip != m_StripUnusedShaders)
                    //{
                    //    dirty = true;
                    //    m_StripUnusedShaders = strip;
                    //}

                    var platform = m_BuildTarget;// (BuildTarget)EditorPrefs.GetInt("MakeAB.platform", 0);
                    BuildTarget target = platform;
                    EditorGUILayout.BeginHorizontal();
                    var settarget = EditorGUILayout.Toggle("Build Platform", platform != BuildTarget.NoTarget);
                    var currentplatform = GetCurrentPlatform();
                    target = platform == BuildTarget.NoTarget ? currentplatform : platform;
                    EditorGUI.BeginDisabledGroup(!settarget);
                    target = (BuildTarget)EditorGUILayout.EnumPopup(target);
                    EditorGUI.EndDisabledGroup();
                    EditorGUILayout.EndHorizontal();
                    target = settarget ? target : BuildTarget.NoTarget;
                    if (target != platform)
                    {
                        dirty = true;
                        m_BuildTarget = target;
                        //EditorPrefs.SetInt("MakeAB.platform", (int)target);
                    }
                    var option = m_BuildOption;// (BuildAssetBundleOptions)EditorPrefs.GetInt("MakeAB.option", 0);
                    var reoption = (BuildAssetBundleOptions)EditorGUILayout.EnumFlagsField("Build Option", option);

#if CHINA_VERSION
#if ENCRYPT_ENABLED
                    reoption |= BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.EnableProtection;
                    reoption &= ~BuildAssetBundleOptions.UncompressedAssetBundle;
#else
                    reoption &= ~BuildAssetBundleOptions.EnableProtection;
#endif
#endif
//#if CHINA_VERSION
//                    var encript = (reoption & BuildAssetBundleOptions.EnableProtection) != 0;
//#else
//                //var encript = false;
//#endif
                    if (reoption != option)
                    {
                        dirty = true;
                        m_BuildOption = reoption;
                        //EditorPrefs.SetInt("MakeAB.option", (int)reoption);
                    }
#if !ENCRYPT_ENABLED || !CHINA_VERSION
                EditorGUILayout.HelpBox("Define symbol of \"ENCRYPT_ENABLED\" + \"CHINA_VERSION\" and make sure that you are using editor's version for China to activite asset protection", MessageType.Info, true);
#else
                    EditorGUI.BeginDisabledGroup(true);
                    var rekey = EditorGUILayout.TextField("Encrypt Key", MakeAB.DEFAULT_KEY);
                    EditorGUI.EndDisabledGroup();
#endif
                    EditorGUILayout.BeginHorizontal();
                    search = GUILayout.Button("搜索打包资源", (GUIStyle)"buttonleft");
                    build = GUILayout.Button("打包 AssetBundle", (GUIStyle)"buttonright");

                    EditorGUILayout.EndHorizontal();
                }
                QuickGUI.EndGroup();
                if (search)
                    FindAssetBundlesJobs();
                if (build)
                    BuildAssetBundles(false);
            }

            void ResovleAssetsGUI(ref bool dirty)
            {
                GUILayout.Space(5);
                var drop = QuickGUI.BeginGroup("Resolve Assets' Problem", dropGroup == 1);
                dirty |= drop ^ (dropGroup == 1);
                bool find = false, find2 = false, find3 = false, clean = false ;
                if (drop)
                {
                    dropGroup = 1;
                    EditorGUI.BeginChangeCheck();
                    assertAsset = EditorGUILayout.TextField("Assert Asset", assertAsset);
                    inAb = EditorGUILayout.TextField("Assets In Bundle", inAb);

                    EditorGUI.indentLevel++;
                    dependentAb = EditorGUILayout.TextField("Dependent In Bundle", dependentAb);
                    notDependentAb = EditorGUILayout.TextField("Dependent Out Bundle", notDependentAb);
                    EditorGUILayout.BeginHorizontal();
                    detailSearchMode = EditorGUILayout.Popup("Search Dependency Mode", detailSearchMode ? 1 : 0, mSearchDependencyMod) == 1;
                    //detailSearchMode = GUILayout.Toggle(detailSearchMode, "Detail Mode");
                    find = GUILayout.Button("Find Dependent Assets", (GUIStyle)"buttonleft");
                    find2 = GUILayout.Button("Find Dependent Assets (Research)", (GUIStyle)"buttonright");
                    EditorGUILayout.EndHorizontal();
                    EditorGUI.indentLevel--;

                    EditorGUILayout.Space();
                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.PrefixLabel("Entire Project's AB");
                    find3 = GUILayout.Button("Find Dependency Circle", (GUIStyle)"buttonleft");
                    clean = GUILayout.Button("Clean Prefab Instance", (GUIStyle)"buttonright");
                    EditorGUILayout.EndHorizontal();

                    dirty |= EditorGUI.EndChangeCheck();
                    AssetsUtil.AssertAsset = assertAsset;
                }
                else
                {
                    AssetsUtil.AssertAsset = null;
                }
                QuickGUI.EndGroup();

                if (find || find2)
                {
                    if (!Directory.Exists("AssetDependencyLog"))
                        Directory.CreateDirectory("AssetDependencyLog");
                    FindDependencyAssets(this, inAb, dependentAb, notDependentAb, "AssetDependencyLog", find2, detailSearchMode);
                }
                if (find3)
                {
                    var cmd = new FindABDependencyCircleCmd("AssetDependencyLog/ABCircles/ABCircle.log");
                    var handler = cmd.Schedule(false);
                    handler.DisplayProgressBar("Find AB Circle", "is processing asset bundles...", true);
                }
                if (clean)
                {
                    var cmd = new ClearInvalidPrefabVariantData();
                    cmd.Schedule(true);
                }
            }

            void RedirectAssetGUI(ref bool dirty)
            {
                GUILayout.Space(5);
                var drop = QuickGUI.BeginGroup("Redirect Assets' Path", dropGroup == 2);
                dirty |= drop ^ (dropGroup == 2);
                bool exportGUID = false, checkRedirect = false/*, applyRedirect = false*/;
                bool cleanGUID = false, selectFolder = false;
                if (drop)
                {
                    //base.OnGUI();
                    EditorGUI.BeginDisabledGroup(mExecJob.IsAlive);
                    dropGroup = 2;
                    EditorGUILayout.BeginHorizontal();
                    var folder = DevilEditorUtility.TextField("GUID Folder", m_GUIDFolder, "Assets/../GUID", "textfield");
                    if (folder != m_GUIDFolder)
                    {
                        dirty = true;
                        m_GUIDFolder = folder;
                    }
                    selectFolder = GUILayout.Button("Select", GUILayout.Width(90));
                    EditorGUILayout.EndHorizontal();
                    EditorGUILayout.BeginHorizontal();
                    var ver = DevilEditorUtility.TextField("Min Version", m_RedirectVersion, "0.0.0", "textfield");
                    if (ver != m_RedirectVersion)
                    {
                        dirty = true;
                        m_RedirectVersion = ver;
                    }
                    cleanGUID = GUILayout.Button("Clean", GUILayout.Width(90));
                    EditorGUILayout.EndHorizontal();

                    EditorGUILayout.BeginHorizontal();
                    exportGUID = GUILayout.Button("导出 GUID 目录", (GUIStyle)"buttonleft");
                    checkRedirect = GUILayout.Button("生成重定向文件", (GUIStyle)"buttonright");
                    //applyRedirect = GUILayout.Button("更新预设体引用", (GUIStyle)"buttonright");
                    EditorGUILayout.EndHorizontal();
                    EditorGUI.EndDisabledGroup();
                }
                QuickGUI.EndGroup();
                if (selectFolder)
                {
                    var folder = EditorUtility.OpenFolderPanel("Select GUID Folder", "Assets/../", "GUID");
                    if (!string.IsNullOrEmpty(folder))
                        m_GUIDFolder = folder;
                }
                if(cleanGUID)
                {
                    var cmd = new CleanGUIDCmd(this);
                    mExecJob = cmd.Schedule(false);
                }
                if (exportGUID)
                {
                    var cmd = new ExportAssetGUID(this);
                    mExecJob = cmd.Schedule(false);
                }
                if(checkRedirect)
                {
                    var cmd = new RedirectAssetCmd(this, Application.version);
                    mExecJob = cmd.Schedule(false);
                }
                //if(applyRedirect)
                //{
                //    var cmd = new ApplyRedirectForPrefabCmd(this);
                //    mExecJob = cmd.Schedule(true);
                //}
            }

        }

    }
}